package com.music.note_android.ui.editor

import android.graphics.*
import android.util.LruCache
import kotlin.math.*

/**
 * 基于点的渲染引擎
 * 专门用于渲染PointDrawing数据，使用点阵而非线条来绘制
 * 确保在任何缩放级别下都能保持一致的视觉效果
 */
class PointRenderingEngine {
    
    // 画笔缓存池
    private val paintPool = mutableListOf<Paint>()
    
    // 不同工具的基础画笔
    private val penPaint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.FILL
    }
    
    private val pencilPaint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.FILL
        alpha = 230
    }
    
    private val highlighterPaint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.FILL
        alpha = 128
    }
    
    private val eraserPaint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.FILL
        xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
    }
    
    // 性能优化：点缓存
    private val pointCache = LruCache<String, List<RenderedPoint>>(50)
    
    // 脏区域管理
    private val dirtyRegions = mutableListOf<RectF>()
    
    /**
     * 渲染单个点绘画
     */
    fun renderPointDrawing(canvas: Canvas, pointDrawing: PointDrawing, scale: Float = 1.0f) {
        if (pointDrawing.isEmpty()) return
        
        val paint = getPaintForTool(pointDrawing.tool)
        configurePaint(paint, pointDrawing)
        
        // 根据工具类型选择不同的渲染方式
        when (pointDrawing.tool) {
            DrawingTool.PEN -> renderPenPoints(canvas, pointDrawing, paint, scale)
            DrawingTool.PENCIL -> renderPencilPoints(canvas, pointDrawing, paint, scale)
            DrawingTool.HIGHLIGHTER -> renderHighlighterPoints(canvas, pointDrawing, paint, scale)
            DrawingTool.ERASER -> renderEraserPoints(canvas, pointDrawing, paint, scale)
        }
    }
    
    /**
     * 渲染多个点绘画
     */
    fun renderPointDrawings(canvas: Canvas, pointDrawings: List<PointDrawing>, scale: Float = 1.0f) {
        pointDrawings.forEach { pointDrawing ->
            renderPointDrawing(canvas, pointDrawing, scale)
        }
    }
    
    /**
     * 渲染钢笔点
     */
    private fun renderPenPoints(canvas: Canvas, pointDrawing: PointDrawing, paint: Paint, scale: Float) {
        pointDrawing.points.forEach { point ->
            val radius = point.getEffectiveRadius(pointDrawing.basePointSize)
            canvas.drawCircle(point.x, point.y, radius, paint)
        }
    }
    
    /**
     * 渲染铅笔点（带纹理效果）
     */
    private fun renderPencilPoints(canvas: Canvas, pointDrawing: PointDrawing, paint: Paint, scale: Float) {
        pointDrawing.points.forEach { point ->
            val radius = point.getEffectiveRadius(pointDrawing.basePointSize)
            
            // 铅笔效果：绘制多个稍微偏移的小圆来模拟纹理
            val texturePoints = generateTexturePoints(point, radius, point.pressure)
            texturePoints.forEach { texturePoint ->
                canvas.drawCircle(
                    texturePoint.x, 
                    texturePoint.y, 
                    texturePoint.radius, 
                    paint
                )
            }
        }
    }
    
    /**
     * 渲染荧光笔点
     */
    private fun renderHighlighterPoints(canvas: Canvas, pointDrawing: PointDrawing, paint: Paint, scale: Float) {
        // 荧光笔使用较大的点和高透明度
        pointDrawing.points.forEach { point ->
            val radius = point.getEffectiveRadius(pointDrawing.basePointSize) * 1.5f
            canvas.drawCircle(point.x, point.y, radius, paint)
        }
    }
    
    /**
     * 渲染橡皮擦点
     */
    private fun renderEraserPoints(canvas: Canvas, pointDrawing: PointDrawing, paint: Paint, scale: Float) {
        pointDrawing.points.forEach { point ->
            val radius = point.getEffectiveRadius(pointDrawing.basePointSize) * 2.0f
            canvas.drawCircle(point.x, point.y, radius, paint)
        }
    }
    
    /**
     * 生成纹理点（用于铅笔效果）
     */
    private fun generateTexturePoints(centerPoint: DrawingPoint, baseRadius: Float, pressure: Float): List<TexturePoint> {
        val texturePoints = mutableListOf<TexturePoint>()
        
        // 主点
        texturePoints.add(TexturePoint(centerPoint.x, centerPoint.y, baseRadius))
        
        // 根据压感生成额外的纹理点
        val textureCount = (pressure * 3).toInt().coerceIn(1, 5)
        val maxOffset = baseRadius * 0.3f
        
        repeat(textureCount) {
            val angle = (it * 2 * PI / textureCount).toFloat()
            val offset = maxOffset * (0.3f + 0.7f * kotlin.random.Random.nextFloat())
            val x = centerPoint.x + cos(angle) * offset
            val y = centerPoint.y + sin(angle) * offset
            val radius = baseRadius * (0.4f + 0.3f * kotlin.random.Random.nextFloat())
            
            texturePoints.add(TexturePoint(x, y, radius))
        }
        
        return texturePoints
    }
    
    /**
     * 获取工具对应的画笔
     */
    private fun getPaintForTool(tool: DrawingTool): Paint {
        return when (tool) {
            DrawingTool.PEN -> penPaint
            DrawingTool.PENCIL -> pencilPaint
            DrawingTool.HIGHLIGHTER -> highlighterPaint
            DrawingTool.ERASER -> eraserPaint
        }
    }
    
    /**
     * 配置画笔属性
     */
    private fun configurePaint(paint: Paint, pointDrawing: PointDrawing) {
        paint.color = pointDrawing.color
        
        // 根据工具类型设置透明度
        when (pointDrawing.tool) {
            DrawingTool.PEN -> {
                paint.alpha = (255 * pointDrawing.alpha).toInt()
            }
            DrawingTool.PENCIL -> {
                paint.alpha = (230 * pointDrawing.alpha).toInt()
            }
            DrawingTool.HIGHLIGHTER -> {
                paint.alpha = (128 * pointDrawing.alpha).toInt()
            }
            DrawingTool.ERASER -> {
                // 橡皮擦不需要设置颜色和透明度
            }
        }
    }
    
    /**
     * 优化渲染：只渲染可见区域内的点
     */
    fun renderPointDrawingInBounds(
        canvas: Canvas, 
        pointDrawing: PointDrawing, 
        visibleBounds: RectF, 
        scale: Float = 1.0f
    ) {
        if (pointDrawing.isEmpty()) return
        
        // 过滤出可见区域内的点
        val visiblePoints = pointDrawing.points.filter { point ->
            val radius = point.getEffectiveRadius(pointDrawing.basePointSize)
            val pointBounds = RectF(
                point.x - radius,
                point.y - radius,
                point.x + radius,
                point.y + radius
            )
            RectF.intersects(visibleBounds, pointBounds)
        }
        
        if (visiblePoints.isEmpty()) return
        
        // 创建临时的PointDrawing只包含可见点
        val visiblePointDrawing = pointDrawing.copy(points = visiblePoints)
        renderPointDrawing(canvas, visiblePointDrawing, scale)
    }
    
    /**
     * 批量渲染优化：合并相近的点
     */
    fun renderOptimizedPointDrawing(
        canvas: Canvas, 
        pointDrawing: PointDrawing, 
        scale: Float = 1.0f,
        mergeThreshold: Float = 2.0f
    ) {
        if (pointDrawing.isEmpty()) return
        
        val optimizedPoints = optimizePoints(pointDrawing.points, mergeThreshold)
        val optimizedDrawing = pointDrawing.copy(points = optimizedPoints)
        
        renderPointDrawing(canvas, optimizedDrawing, scale)
    }
    
    /**
     * 优化点列表：合并距离过近的点
     */
    private fun optimizePoints(points: List<DrawingPoint>, threshold: Float): List<DrawingPoint> {
        if (points.size <= 1) return points
        
        val optimized = mutableListOf<DrawingPoint>()
        optimized.add(points[0])
        
        for (i in 1 until points.size) {
            val lastPoint = optimized.last()
            val currentPoint = points[i]
            
            if (lastPoint.distanceTo(currentPoint) >= threshold) {
                optimized.add(currentPoint)
            }
        }
        
        return optimized
    }
    
    /**
     * 添加脏区域
     */
    fun addDirtyRegion(bounds: RectF) {
        dirtyRegions.add(RectF(bounds))
    }
    
    /**
     * 获取脏区域列表
     */
    fun getDirtyRegions(): List<RectF> {
        return dirtyRegions.toList()
    }
    
    /**
     * 清除脏区域
     */
    fun clearDirtyRegions() {
        dirtyRegions.clear()
    }
    
    /**
     * 清理缓存
     */
    fun clearCache() {
        pointCache.evictAll()
        dirtyRegions.clear()
    }
    
    /**
     * 纹理点数据类
     */
    private data class TexturePoint(
        val x: Float,
        val y: Float,
        val radius: Float
    )
    
    /**
     * 渲染点数据类
     */
    private data class RenderedPoint(
        val x: Float,
        val y: Float,
        val radius: Float,
        val color: Int,
        val alpha: Int
    )
    
    /**
     * 获取渲染统计信息
     */
    fun getStatistics(): PointRenderingStatistics {
        return PointRenderingStatistics(
            pointCacheSize = pointCache.size(),
            paintPoolSize = paintPool.size,
            dirtyRegionCount = dirtyRegions.size
        )
    }
    
    /**
     * 渲染统计信息数据类
     */
    data class PointRenderingStatistics(
        val pointCacheSize: Int,
        val paintPoolSize: Int,
        val dirtyRegionCount: Int
    )
}